package com.swan.security.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.swan.security.auto.config.SecurityConfig;
import com.swan.security.security.IApiSelector;
import com.swan.security.token.JwtTokenManager;
import com.swan.security.domain.SecurityUserInfo;
import com.swan.web.auto.config.SpringWebConfig;
import com.swan.web.domain.BaseResponse;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;

/** 用户登录拦截器:    <br/>
 * 1. 校验用户 Token 合法性    <br/>
 * 2. 从 token 中解析用户基本信息，封装到 security 上下文中     <br/>
 * 3. 查询用户拥有的 api 权限，并封装到上下文中     <br/>
 * @author zongf
 * @date 2025-02-19
 */
@Slf4j
public class AuthLoginInterceptor extends OncePerRequestFilter {

    @Autowired
    private JwtTokenManager jwtTokenProvider;

    @Autowired
    private SecurityConfig securityConfig;

    @Autowired
    private SpringWebConfig springWebConfig;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Autowired
    private IApiSelector apiSupplier;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String requestUri = request.getRequestURI().substring(springWebConfig.getServerContextPath().length());

        // 公开接口, 不需要校验用户登录
        boolean isPublicPath = securityConfig.getPublicPath().stream().anyMatch(url -> antPathMatcher.match(url, requestUri));
        if (isPublicPath) {
            filterChain.doFilter(request, response);
            return;
        }


        // 从 Request Header 中解析 token
        String token = jwtTokenProvider.resolveToken(request);

        log.info("[校验用户登录] token:{}", token);

        // 校验 JWT Token 的合法性, 例如，检查 token 是否过期、是否篡改等。如果 token 无效或过期，认证过程会被跳过，后续请求会被拒绝。
        if(StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)){
            // 从 token 中解析用户信息
            SecurityUserInfo securityUserInfo = jwtTokenProvider.getUserInfo(token);

            // 查询接口权限
            List<String> authUrls = this.apiSupplier.queryAuthApis(securityUserInfo);
            List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(authUrls);

            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(securityUserInfo, null, authorityList);
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            // 将身份认证信息（即 authenticationToken）存储在 Spring Security 的上下文中。
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);

            filterChain.doFilter(request, response);
        }else {
            log.warn("JWT Token is missing or invalid");
            SecurityContextHolder.clearContext();

            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            response.getWriter().write(JSONObject.toJSONString(BaseResponse.fail(HttpServletResponse.SC_UNAUTHORIZED, "token 过期，请重新登录")));
        }

    }

}


